var Socket = require('socket.io');
var Log = require('./log');
var listen_port = 8000;
//msg = {id : "loginhandler",type = MSG_REQUEST,data = {"a":12345} ,rid [optional] request unquiue id}
//
var MSG_TYPE = {
    MSG_REQUEST : 1,
    MSG_RESPONSE: 2,
    MSG_NOTIFY: 3,
};

//max time request wait respond
var REQUEST_INVALID_TIME = 10000;

function Session(socket,id){
    this.socket = socket;
    this.id = id;
    this.__player = null;
    this.requestCallbacks = {};
}

Session.prototype.getPlayer = function(){
    return this.__player;
};

Session.prototype.packMessage = function(msg,type){
    msg.type = type;
    if(msg.type === MSG_TYPE.MSG_REQUEST){
        do{
            msg.rid = Math.floor(Math.random() * 2147483648);
        }while(this.requestCallbacks[msg.rid]);
    }
    return msg;
};

Session.prototype.pushRequestCallback = function(rid,cb){
    var d = new Date();
    var time = d.getTime();
    this.requestCallbacks[rid] = [cb,time];
};

Session.prototype.invokeCallback = function(rid,params){
    if(this.requestCallbacks[rid]){
        var cb = this.requestCallbacks[rid][0];
        cb.call(this,this,params);
    }
};

Session.prototype.removeOvertimeRequest = function(){
    var d = new Date();
    var time = d.getTime();
    for(var id in this.requestCallbacks){
        if(time > this.requestCallbacks[id][1] + REQUEST_INVALID_TIME){
            Log.debug("delete request overtime,request = %s",JSON.stringify(this.requestCallbacks[id][0]));
            delete this.requestCallbacks[id];
        }
    }
}

Session.prototype.attachPlayer = function(player){
    this.__player = player;
};

Session.prototype.disconnect = function(){
    if(this.__player){
        this.__player.onDisconnect();
    }
    app.getNetService().getSessionManager().delSession(this.id);
    this.socket.disconnect();
};

Session.prototype.registerEvents = function(){
    var self = this;
    this.socket.on("message",function(data){
       // try{
            var msg = null;
            try{
                msg = JSON.parse(data);
            }catch(err){
                Log.warn("[ERROR]:MSG PARSER ERROR,%s",err);
                self.disconnect();
                return;
            }
            var msg = JSON.parse(data);
            Log.msg("[MSG]:RECV:%s",data);
            //登陆前不接受其他消息
            if(!self.__player && msg.id !== "Login"){
                self.disconnect();
                return;
            }
            if(msg.type === MSG_TYPE.MSG_REQUEST ){
                if(!app.getHandlerService().isRegisteredMsg(msg)){
                    Log.warn("[ERROR]:MSG NOT REGISTER,%s",data);
                    return;
                }
                var ret =  app.getHandlerService().handleMsg(self,msg);
                if(ret){
                    var response = {rid :msg.rid,data:ret};
                    self.send(self.packMessage(response,MSG_TYPE.MSG_RESPONSE));
                }else{
                    Log.warn("[ERROR]:REQUEST MSG WITHOUT RESPONSE",data);
                }
            }else if(msg.type === MSG_TYPE.MSG_RESPONSE){
                self.invokeCallback(msg.rid,msg.data);
            }else if(msg.type === MSG_TYPE.MSG_NOTIFY){
                if(!app.getHandlerService().isRegisteredMsg(msg)){
                    Log.warn("[ERROR]:MSG NOT REGISTER,%s",data);
                    return;
                }
                app.getHandlerService().handleMsg(self,msg);
            }else{

            }
      //  }
      //  catch(err){
     //       Log.warn("[ERROR]:ERROR MSG,%s,%s",err,data);
      //      this.disconnect();
     //   }
    });
    this.socket.on("disconnect",function(){
        if(self.__player){
            self.__player.onDisconnect();
        }
        app.getNetService().getSessionManager().delSession(self.id);
        Log.debug("socket disconnected, id = %s",JSON.stringify(self.id));
    });
}

Session.prototype.send = function(msg){
    var data = JSON.stringify(msg);
    this.socket.send(data);
    Log.msg("[MSG]:SEND:%s",data);
};

Session.prototype.request = function(msg,cb){
    var msg = this.packMessage(msg,MSG_TYPE.MSG_REQUEST);
    this.pushRequestCallback(msg.rid,cb);
    this.send(msg);
};

Session.prototype.notify = function(msg){
    var msg = this.packMessage(msg,MSG_TYPE.MSG_NOTIFY);
    this.send(msg);
};

var SessionManager =function(){
    this.sessions = {};
    this.sessionIds = {};
    this.total_session = 0;
};

SessionManager.prototype.newSessionId = function(){
    var id = 0;
    while(this.sessionIds.hasOwnProperty(id)){
        id = Math.floor(Math.random() * 65535);
    }
    return id;
}

SessionManager.prototype.newSession = function(socket){
    var id = this.newSessionId();
    this.sessionIds[id] = true;
    if(this.sessions.hasOwnProperty(id)){
        Log.debug("new session, id already exists, id = %s",id);
        return null;
    }
    var session = new Session(socket,id);
    this.sessions[id] = new Session(socket,id);
    this.total_session++;
    Log.debug("new session, id = %s,total session num = %d",id,this.total_session);
    return this.sessions[id];
};

SessionManager.prototype.delSession = function(id){
    if(this.sessions.hasOwnProperty(id)){
        delete this.sessions[id];
        this.total_session--;
        Log.debug("del session, id = %s,total session num = %d",id,this.total_session);
    } else{
        Log.warn("[ERROR]del session not exists, id = %s,total session num = %d",id,this.total_session);
    }
    delete this.sessionIds[id];
};

function NetService(app){
    this.app = app;
    this.sessionManager = new SessionManager();
    this.MSG_TYPE = MSG_TYPE;
}

NetService.prototype.getSessionManager = function(){
    return this.sessionManager;
};

NetService.prototype.start = function(){
    var io = Socket.listen(listen_port);
    io.set('log level', 1);
    var self = this;
    io.sockets.on("connection",function(socket){
        self.onNewSocket(socket);
    });
    Log.debug("NetService started,listen on %d",listen_port);
}

NetService.prototype.onNewSocket = function(socket){
    var session = this.getSessionManager().newSession(socket);
    session.registerEvents();
    Log.debug("New socket accepted,address = %s",JSON.stringify(socket.handshake.address));
};

module.exports = NetService;
